#include "AsyncLogger.h"
#include "Message.h"
#include "CliBackupLog.h"

namespace mylog
{
    AsyncLogger::AsyncLogger(const std::string& loggerName, std::vector<LogFlush::ptr>& flushs, AsyncType type, std::string_view pattern, mylog::LogLevel::value level)
        : logger_name_(loggerName)
        , flushs_(flushs.begin(), flushs.end())
        , formatter_(std::make_shared<LogFormatter>(pattern))
        , asyncworker_(std::make_shared<AsyncWorker>(std::bind(&AsyncLogger::realFlush, this, std::placeholders::_1), type))
        , tp_(std::make_unique<ThreadPool>(mylog::Util::JsonData::GetJsonData()->thread_count))
        , level_(level)
    {
    }

    void AsyncLogger::serialize(LogLevel::value level, const std::string& filename, size_t line, const std::string& payload) 
    {
        if (level < level_)
            return;
        auto msg = std::make_shared<LogMessage>(level, filename, line, logger_name_, payload);
        std::string data = formatter_->format(msg);
        if (level == LogLevel::value::FATAL || level == LogLevel::value::ERROR)
        {
            // 备份日志到日志备份服务器，这里先不管
            try 
            {
                auto ret = tp_->enqueue(start_backup, data);
                // 同步确保日志备份成功，否则在错误的情况下干其他事可能会导致崩溃而记录失败
                ret.get();
            }
            catch(const std::runtime_error& e)
            {
                std::cerr << __FILE__ << __LINE__ << "thread pool closed\n";
            }
        }
        // 输出到异步缓冲区，接下来由异步worker输出
        flush(data.c_str(), data.size());
    }

    void AsyncLogger::flush(const char* data, size_t len)
    {
        // push函数本身是线程安全的，因此不需要同步机制
        asyncworker_->push(data, len);
    }

    void AsyncLogger::realFlush(Buffer& buffer)
    {
        if (flushs_.empty())
            return;
        for (auto& e : flushs_) 
        {
            e->flush(buffer.begin(), buffer.readableSize());
        }
    }

    void AsyncLogger::debug(const std::string& msg, std::source_location loc)
    {
        serialize(LogLevel::value::DEBUG, loc.file_name(), loc.line(), msg);
    }

    void AsyncLogger::info(const std::string& msg, std::source_location loc)
    {
        serialize(LogLevel::value::INFO, loc.file_name(), loc.line(), msg);
    }

    void AsyncLogger::warn(const std::string& msg, std::source_location loc)
    {
        serialize(LogLevel::value::WARN, loc.file_name(), loc.line(), msg);
    }

    void AsyncLogger::error(const std::string& msg, std::source_location loc)
    {
        serialize(LogLevel::value::ERROR, loc.file_name(), loc.line(), msg);
    }

    void AsyncLogger::fatal(const std::string& msg, std::source_location loc)
    {
        serialize(LogLevel::value::FATAL, loc.file_name(), loc.line(), msg);
    }

} // namespace log
